package com.core.common;

import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileWriter;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 日志
 */
@Slf4j
public class Rog {
    //0 控制台打印，1 log 打印 2 独立文件 3 log和独立文件
    public static Integer logLevel = 3;
    //执行线程
    private static ExecutorService es = Executors.newSingleThreadExecutor();
    //文件名称
    private static Map<String, Map<String, FileWriter>> writeLogMap = new HashMap<>();

    /**
     * 取得名称
     *
     * @param logName
     * @return
     */
    private static synchronized FileWriter getWriter(String moduleName, String logName) {
        //日期
        String nowDate = DateUtil.format(new Date(), "yyyyMMdd");
        //不包含，就是新的一天，清理掉旧的数据
        if (!writeLogMap.containsKey(nowDate)) {
            for (Map<String, FileWriter> writeMap : writeLogMap.values()) {
                for (FileWriter w : writeMap.values()) {
                    try {
                        w.close();
                    } catch (Exception ex) {
                    }
                }
            }
            writeLogMap.clear();
            //添加新的
            writeLogMap.put(nowDate, new HashMap<>());
        }
        try {
            Map<String, FileWriter> logMap = writeLogMap.get(nowDate);
            if (logMap == null) {
                logMap = new HashMap<>();
            }
            String key = moduleName +"/"+logName;
            FileWriter w = logMap.get(key);
            if (w == null) {
                File file = new File("/home/business/" + moduleName + "/" + logName + ".log");
                if (!file.exists()) {
                    file.setExecutable(true);
                    file.setWritable(true);
                    file.setReadable(true);
                    file.getParentFile().mkdirs();
                    file.createNewFile();
                }
                // 使用FileWriter构造函数创建文件输出流
                w = new FileWriter(file, true);
                logMap.put(key, w);
            }
            return w;
        } catch (Exception ex) {
            log.error("创建日志文件失败！",ex);
            throw new RuntimeException(ex);
        }

    }

    //模块名称
    private String moduleName;
    //日志文件
    private String logName;

    /**
     * 构造函数
     *
     * @param moduleName
     * @param logName
     */
    private Rog(String moduleName, Object logName) {
        this.moduleName = moduleName;
        this.logName = logName.toString();
    }

    /**
     * 构造函数
     *
     * @param logName
     * @return
     */
    public static Rog build(Object logName) {
        return build("logs", logName);
    }


    /**
     * 构造函数
     *
     * @param moduleName
     * @param logName
     * @return
     */
    public static Rog build(String moduleName, Object logName) {
        return new Rog(moduleName, logName);
    }

    /**
     * Log a message at the DEBUG level.
     *
     * @param msg the message string to be logged
     */
    public Rog debug(String msg, Object... values) {
        if (Rog.logLevel == 1 || Rog.logLevel == 3) {
            log.debug(msg, values);
        }
        if (Rog.logLevel == 2 || Rog.logLevel == 3) {
            append(this.moduleName, this.logName, format(msg, values));
        }
        if (Rog.logLevel == 0) {
            System.out.println(format(msg, values));
        }
        return this;
    }

    /**
     * Log a message at the INFO level.
     *
     * @param msg the message string to be logged
     */
    public Rog info(String msg, Object... values) {
        if (Rog.logLevel == 1 || Rog.logLevel == 3) {
            log.info(msg, values);
        }
        if (Rog.logLevel == 2 || Rog.logLevel == 3) {
            append(this.moduleName, this.logName, format(msg, values));
        }
        if (Rog.logLevel == 0) {
            System.out.println(format(msg, values));
        }
        return this;
    }

    /**
     * Log a message at the DEBUG level.
     *
     * @param msg the message string to be logged
     */
    public Rog error(String msg, Object... values) {
        if (Rog.logLevel == 1 || Rog.logLevel == 3) {
            log.error(msg, values);
        }
        if (Rog.logLevel == 2 || Rog.logLevel == 3) {
            append(this.moduleName, this.logName, format(msg, values));
        }
        if (Rog.logLevel == 0) {
            System.out.println(format(msg, values));
        }
        return this;
    }

    /**
     * 格式化
     *
     * @param msg
     * @param values
     * @return
     */
    private String format(String msg, Object... values) {
        String[] ms = msg.split("\\{\\}");
        StringBuilder s = new StringBuilder();
        int idx = 0;
        for (String m : ms) {
            s.append(m);
            if (values != null && values.length > idx) {
                if (values[idx++] != null) {
                    s.append(values[idx++].toString());
                }
            }
        }
        return s.toString();
    }

    /**
     * Log a message at the INFO level.
     *
     * @param msgs the message string to be logged
     */
    public Rog log(String... msgs) {
        if (Rog.logLevel == 2 || Rog.logLevel == 3) {
            append(this.moduleName, this.logName, msgs);
        }
        if (Rog.logLevel == 0) {
            System.out.println(FnKit.join(Arrays.asList(msgs), "\r\n"));
        }
        return this;
    }


    /**
     * Log a message at the INFO level.
     *
     * @param msgList the message string to be logged
     */
    public Rog log(List<String> msgList) {
        if (msgList == null || msgList.size() == 0) {
            return this;
        }
        if (Rog.logLevel == 2 || Rog.logLevel == 3) {
            append(this.moduleName, this.logName, msgList.toArray(new String[0]));
        }
        if (Rog.logLevel == 0) {
            System.out.println(FnKit.join(msgList, "\r\n"));
        }
        return this;
    }


    /**
     * 添加日志
     *
     * @param moduleName
     * @param logName
     * @param contentList
     */
    private static void append(final String moduleName, final String logName, final String... contentList) {
        if (logName == null || logName.length() == 0) {
            return;
        }
        if (contentList == null || contentList.length == 0) {
            return;
        }
        //提交，包装顺序执行
        es.submit(() -> {
            try {
                FileWriter w = getWriter(moduleName, logName);
                if (w != null) {
                    SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
                    String date = f.format(new Date());
                    StringBuilder sb = new StringBuilder();
                    for (String content : contentList) {
                        sb.append(date).append(" [INFO] :").append(content).append("\r\n");
                    }
                    w.write(sb.toString());
                    w.flush();
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        });
    }


}
